import {dialogStack, Bus} from "@/utils/metadata";

const SIMPLE_TYPES = ['int', 'long', 'float', 'double', 'short', 'byte', 'string', 'date'];
const MAPPINGS = {
    '[Z':'boolean[]',
    '[B':'byte[]',
    '[S':'short[]',
    '[C':'char[]',
    '[I':'int[]',
    '[J':'long[]',
    '[F':'float[]',
    '[D':'double[]'
};

export function cancel_select () {
    return false;
}

export function patchTypeName (name) {
    if (name[0] !== '[') {
        return name;
    }

    if (name[1] === 'L') {
        return name.substring (2, name.length - 1) + '[]';
    }

    if (name in MAPPINGS) {
        return MAPPINGS [name];
    }
    throw "Unknown Type!";
}

export function patchItems (srf) {
    srf.id = Math.random().toString ().substring (2);

    if ('items' in srf) {
        let item, i, j, k, method, parameter;
        for (k in srf.items) if (srf.items.hasOwnProperty (k)) {
            item = srf.items [k];

            if (('types' in item) && item.types.length) {
                for (i = 0; i < item.types.length; i ++) {
                    item.types [i] = patchTypeName (item.types [i]);
                }
            }

            if (('methods' in item) && item.methods.length) {
                for (i = 0; i < item.methods.length; i ++) {
                    method = item.methods[i];
                    method.type = patchTypeName (method.type);

                    if (('parameters' in method) && method.parameters.length) {
                        for (j = 0; j < method.parameters.length; j ++) {
                            parameter = method.parameters[j];
                            parameter.type = patchTypeName (parameter.type);
                        }
                    }
                }
            }
        }
    }

    return srf;
}

export function closeDialog (e) {
    if (e.keyCode === 27) {
        if (dialogStack.length) {
            let uuid = dialogStack [dialogStack.length - 1];
            if (uuid) {
                console.log ('acquire to close dialog: %s', uuid);
                Bus.emit ('close-dialog', uuid);
            }
        }
    }
}


export function noop () {}

export function getSimpleName (raw) {
    if (!raw) {
        console.log ('raw = ', raw);
        return raw;
    }
    let pos = raw.lastIndexOf ('.');
    if (pos >= 0) {
        return raw.substring (pos + 1);
    }
    return raw;
}

export function buildWebSocketURL () {
    let protocol = window.location.protocol,
        hostname = window.location.hostname,
        port     = window.location.port;
    let url      = (protocol === 'http:' ? 'ws' : 'wss') + '://' + hostname;
    if (port && port !== "80" && port !== '443') {
        url += ':' + port;
    }
    url += '/monitor/ws/monitor';
    return url;
}

export function isSimpleType (raw) {
    let type = getSimpleName (raw);
    return SIMPLE_TYPES.includes (type.toLowerCase ());
}

export function isCollection (raw) {
    if (!raw) {
        return false;
    }
    raw = raw.toLowerCase ();
    return ['java.util.set', 'java.util.list'].includes (raw);
}

export function isBoolean (raw) {
    let type = getSimpleName (raw);
    if (type) {
        return type.toLowerCase () === 'boolean';
    }
    return false;
}

export function nullable (raw) {
    let type = getSimpleName (raw);
    if (type === 'boolean') return false;
    return type === 'Boolean';

}

export function clone (src) {
    return JSON.parse (JSON.stringify (src));
}

export function buildResult (invocation, response, method) {
    let result = {
        // method signature
        signature: invocation.namespace + '::' + invocation.service + '::' + method.name,
        returnType: method.type,
        description: method.description,
        // success: response.code === 0
    };

    // method arguments

    let args = [], ps = method.parameters;
    for (let i = 0, n = ps.length; i < n; i ++) {
        let type = ps[i].type, name = ps[i].name || '$' + i,
            desc = ps[i].description, temp = JSON.parse (invocation.parameters),
            value = temp[i] === null ? '<span class="null-value">&lt;null&gt;</span>' : temp[i];
        args.push ({type, name, desc, value});
    }
    result.args = args;
    result.success = response.code === 0;

    if (result.success) {
        if (isSimpleType (method.type))
            result.value = response.result;
        else if (method.type.endsWith ('[]') || // 数组
            isCollection (method.type)) { // java 集合
            result.value = JSON.parse (response.result).join (',\n');
        } else {
            let temp = JSON.parse (response.result);
            result.value = JSON.stringify (temp, null, 4);
        }
    } else if (response.code === 500) {
        let ex = JSON.parse (response.result);
        console.error (ex);
        if (ex.error) {
            let type = ex.type;
            ex = ex.error;
            let s = ex.detailMessage + '\n' + type + '\n';
            if (ex.stackTrace) {
                for (let i = 0, n = ex.stackTrace.length; i < n; i ++) {
                    let trace = ex.stackTrace [i];
                    if (i > 0) s += '\n';
                    s += '\tat ' + trace.declaringClass + '.' + trace.methodName +
                        ' (' + trace.fileName + ':' + trace.lineNumber + ')';
                }
                result.stackTrace = s;
            }
        }
    }
    return result;
}

if (!('format' in Date.prototype)) {
    Date.prototype.format = function (fmt) {
        let ret;
        fmt = fmt || 'yyyy-MM-dd';
        const opt = {
            "y+":  this.getFullYear().toString(),        // 年
            "M+": (this.getMonth() + 1).toString(),      // 月
            "d+":  this.getDate().toString(),            // 日
            "H+":  this.getHours().toString(),           // 时
            "m+":  this.getMinutes().toString(),         // 分
            "s+":  this.getSeconds().toString(),         // 秒
            'S+':  this.getMilliseconds().toString (),   // 毫秒
            // 有其他格式化字符需求可以继续添加，必须转化成字符串
        };
        for (let k in opt) {
            ret = new RegExp("(" + k + ")").exec(fmt);
            if (ret) {
                fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
            }
        }
        return fmt;
    };
}